package zh.dummy.netty.server.context;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import io.netty.channel.Channel;
import zh.dummy.netty.NettyServer;
import zh.dummy.netty.server.context.listener.WorkflowListener;

public class NettyManager {
	
	private final static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
	
	private ListenerManager listenerManager;
	
	private NettyServer nettyServer;
	
	private int port;
	
	private volatile static NettyManager nettyManager;
	
	private volatile Map<String,Channel> channelMap;
	
	private NettyManager(){
		setListenerManager(new ListenerManager());
		setNettyServer(NettyServer.getInstance());
		channelMap = new ConcurrentHashMap<String,Channel>();
		nettyManager = this;
	}
	
	public void startNettyServer() {
		nettyServer.bind(port);
		nettyServer.start();
		startCheckChannelSchedule();
	}

	private void startCheckChannelSchedule() {
		executor.scheduleAtFixedRate(new ChannelCheck(), 0, 60, TimeUnit.SECONDS);
	}

	class ChannelCheck implements Runnable{

		@Override
		public void run() {
			if(channelMap != null){
				Set<String> keys = channelMap.keySet();
				for(String key : keys){
					Channel channel = getChannel(key);
					if(!channel.isActive() || !channel.isOpen()){
						channel.close();
						removeChannel(key);
					}
				}
			}
		}
		
	}
	
	public static NettyManager getInstance(){
		if(nettyManager == null){
			synchronized (NettyManager.class) {
				nettyManager = new NettyManager();
			}
		}
		return nettyManager;
	}
	
	public ListenerManager getListenerManager() {
		return listenerManager;
	}

	public void setListenerManager(ListenerManager listenerManager) {
		this.listenerManager = listenerManager;
	}

	public NettyServer getNettyServer() {
		return nettyServer;
	}

	public void setNettyServer(NettyServer nettyServer) {
		this.nettyServer = nettyServer;
	}

	public Set<String> channelKeySet() {
		return channelMap.keySet();
	}

	public Channel getChannel(String key) {
		return channelMap.get(key);
	}
	
	public void setWorkflowListeners(Set<WorkflowListener> listeners){
		listenerManager.addListeners(listeners);
	}
	
	public void setWorkflowListener(WorkflowListener listener){
		listenerManager.addListener(listener);
	}
	public Collection<? extends WorkflowListener> getListeners() {
		return listenerManager.getListeners();
	}

	public void putChannel(String key, Channel channel) {
		channelMap.put(key, channel);
	}
	
	public void setPort(int port){
		this.port = port;
	}

	public void removeChannel(String key) {
		channelMap.remove(key);
	}

	public boolean containsChannel(String key) {
		return channelMap.containsKey(key);
	}
	
}
